package com.ildepinc.persistence.concretes;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.sql.ResultSet;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.HashMap;

import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;

import com.ildepinc.persistence.abstracts.DaoTableAuditable;
import com.ildepinc.persistence.concretes.daos.DaoLanguage;
import com.ildepinc.persistence.concretes.models.Language;

@TestMethodOrder(OrderAnnotation.class)
class DaoLanguageTest {

  private static Persistence persistenceLayer;
  private DaoLanguage daoLanguage;
  private Timestamp currentTimestamp = new Timestamp(System.currentTimeMillis());
  private String currentUser = "testUser";

  @BeforeAll
  static void setUpBeforeClass() throws Exception {
    persistenceLayer = new Persistence();
  }

  @Test
  @Order(1)
  void testStartLayer() {
    assertTrue(persistenceLayer.startLayer());
  }

  @Test
  @Order(2)
  void testDropSequence() {
    String sqlDrop = persistenceLayer.getSequenceGenericMap().get("LanguageSequence").getSqlDrop();
    try {
      persistenceLayer.getStatement().execute(sqlDrop);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  @Test
  @Order(3)
  void testManualDeleteTableAuditable() {
    this.daoLanguage = (DaoLanguage) persistenceLayer.getDaoTableAuditableMap().get("DaoLanguage");
    assertTrue(this.daoLanguage instanceof DaoTableAuditable);
    String deleteSql = this.daoLanguage.getTable().getSqlDelete();
    this.daoLanguage.setSqlCommand(deleteSql);
    ArrayList<Object> sqlParameters = new ArrayList<Object>();
    sqlParameters.add(2L);
    this.daoLanguage.setSqlParameters(sqlParameters);
    Integer rowsAffected = 0;
    try {
      rowsAffected = this.daoLanguage.doManualDmlOrDdl();
    } catch (Exception e) {
      e.printStackTrace();
    }
    assertTrue((rowsAffected == 0) || (rowsAffected == 1));
  }

  @Test
  @Order(4)
  void testDeleteTableAuditable() {
    this.daoLanguage = (DaoLanguage) persistenceLayer.getDaoTableAuditableMap().get("DaoLanguage");
    assertTrue(this.daoLanguage instanceof DaoTableAuditable);
    Integer rowsAffected = 0;
    HashMap<String, Object> primaryKeys = new HashMap<String, Object>();
    primaryKeys.put("ID", 1L);
    try {
      rowsAffected = this.daoLanguage.doDelete(primaryKeys);
    } catch (Exception e) {
      e.printStackTrace();
    }
    assertTrue((rowsAffected == 0) || (rowsAffected == 1));
  }

  @Test
  @Order(5)
  void testCreateSequence() {
    String sqlCreate = persistenceLayer.getSequenceGenericMap().get("LanguageSequence").getSqlCreate();
    try {
      persistenceLayer.getStatement().execute(sqlCreate);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  @Test
  @Order(6)
  void testInsertTableUpdateable() {
    this.daoLanguage = (DaoLanguage) persistenceLayer.getDaoTableAuditableMap().get("DaoLanguage");
    assertTrue(this.daoLanguage instanceof DaoTableAuditable);
    Integer rowsAffected = 0;
    Language language = new Language(
      null, "it", "Italian",
      this.currentTimestamp, this.currentUser,
      this.currentTimestamp, this.currentUser,
      "devschema"
    );
    this.daoLanguage.setTable(language);
    try {
      rowsAffected = this.daoLanguage.doInsert(language, null);
    } catch (Exception e) {
      e.printStackTrace();
    }
    assertEquals(1, rowsAffected);
  }

  @Test
  @Order(7)
  void testUpdateTableUpdatable() {
    this.daoLanguage = (DaoLanguage) persistenceLayer.getDaoTableAuditableMap().get("DaoLanguage");
    assertTrue(this.daoLanguage instanceof DaoTableAuditable);
    Integer rowsAffected = 0;
    Language language = new Language(
      1L, "it", "Italian",
      this.currentTimestamp, this.currentUser,
      this.currentTimestamp, this.currentUser,
      "devschema"
    );
    this.daoLanguage.setTable(language);
    try {
      rowsAffected = this.daoLanguage.doUpdate(language);
    } catch (Exception e) {
      e.printStackTrace();
    }
    assertEquals(1, rowsAffected);
  }

  @Test
  @Order(8)
  void testSelectTableAuditable() {
    this.daoLanguage = (DaoLanguage) persistenceLayer.getDaoTableAuditableMap().get("DaoLanguage");
    assertTrue(this.daoLanguage instanceof DaoTableAuditable);
    Language language = null;
    HashMap<String, Object> primaryKeys = new HashMap<String, Object>();
    primaryKeys.put("ID", 1L);
    try {
      language = (Language) this.daoLanguage.doSelect(primaryKeys);
    } catch (Exception e) {
      e.printStackTrace();
    }
    assertEquals(1L, language.getId());
  }

  @Test
  @Order(9)
  void testManualInsertTableAuditable() {
    this.daoLanguage = (DaoLanguage) persistenceLayer.getDaoTableAuditableMap().get("DaoLanguage");
    assertTrue(this.daoLanguage instanceof DaoTableAuditable);
    String insertSql = this.daoLanguage.getTable().getSqlInsert();
    this.daoLanguage.setSqlCommand(insertSql);
    ArrayList<Object> sqlParameters = new ArrayList<Object>();
    sqlParameters.add(2L);
    sqlParameters.add("en");
    sqlParameters.add("English");
    sqlParameters.add(this.currentTimestamp);
    sqlParameters.add(this.currentUser);
    sqlParameters.add(this.currentTimestamp);
    sqlParameters.add(this.currentUser);
    this.daoLanguage.setSqlParameters(sqlParameters);
    Integer rowsAffected = 0;
    try {
      rowsAffected = this.daoLanguage.doManualDmlOrDdl();
    } catch (Exception e) {
      e.printStackTrace();
    }
    assertEquals(1, rowsAffected);
  }

  @Test
  @Order(10)
  void testManualUpdateTableAuditable() {
    this.daoLanguage = (DaoLanguage) persistenceLayer.getDaoTableAuditableMap().get("DaoLanguage");
    assertTrue(this.daoLanguage instanceof DaoTableAuditable);
    String updateSql = this.daoLanguage.getTable().getSqlUpdate();
    this.daoLanguage.setSqlCommand(updateSql);
    ArrayList<Object> sqlParameters = new ArrayList<Object>();
    sqlParameters.add("en");
    sqlParameters.add("English");
    sqlParameters.add(this.currentTimestamp);
    sqlParameters.add(this.currentUser);
    sqlParameters.add(2L);
    this.daoLanguage.setSqlParameters(sqlParameters);
    Integer rowsAffected = 0;
    try {
      rowsAffected = this.daoLanguage.doManualDmlOrDdl();
    } catch (Exception e) {
      e.printStackTrace();
    }
    assertEquals(1, rowsAffected);
  }

  @Test
  @Order(11)
  void testManualSelectTableAuditable() {
    this.daoLanguage = (DaoLanguage) persistenceLayer.getDaoTableAuditableMap().get("DaoLanguage");
    assertTrue(this.daoLanguage instanceof DaoTableAuditable);
    String selectSql = this.daoLanguage.getTable().getSqlSelect();
    this.daoLanguage.setSqlCommand(selectSql);
    ArrayList<Object> sqlParameters = new ArrayList<Object>();
    sqlParameters.add(2L);
    this.daoLanguage.setSqlParameters(sqlParameters);
    ResultSet resultSet = null;
    Long retriviedId = 0L;
    try {
      resultSet = this.daoLanguage.doManualSelect();
      resultSet.first();
      retriviedId = resultSet.getLong(1);
    } catch (Exception e) {
      e.printStackTrace();
    }
    assertEquals(2L, retriviedId);
  }

  @Order(12)
  void testStopLayer() {
    assertTrue(persistenceLayer.stopLayer());
  }

  @AfterAll
  static void tearDownAfterClass() throws Exception {
    persistenceLayer = null;
  }

}
